#include "work_group_size.h"

int omd_work_group_size_optimize( ocl_kernel *kernel, const ocl_device *device, const size_t global_work_size, size_t *local_work_size )
{
	assert( kernel );
	assert( device );
	assert( global_work_size > 0    );
	assert( local_work_size != NULL );
	
	{
		size_t work_group_size = 0;
		
		if( ocl_get_kernel_work_group_size(kernel, device, &work_group_size) < 0 )
		{
			return -1;
		}
		assert( work_group_size > 0 );
		
		if( ocl_logfile ) { fprintf( ocl_logfile, "[omd_work_size_optimize] max work_group_size= %u\n", (unsigned) work_group_size ); }
		if( *local_work_size < work_group_size )
		{
			work_group_size = *local_work_size;
		}
		
		if( work_group_size <= 1 )
		{
			*local_work_size = 1;
			return 0;
		}
		
		assert( work_group_size > 0 );
		/** compatible size */
		while( 0 != (global_work_size % work_group_size) ) --work_group_size;
		
		/** fit in size */
		while( work_group_size * (3*sizeof(Real4)) > device->LOCAL_MEM_SIZE ) --work_group_size;
		
		/** compatible size */
		while( 0 != (global_work_size % work_group_size) ) --work_group_size;
		
		*local_work_size = work_group_size;
		return 0;
	}
}
